package com.fadadianqi.logistics.sell.service;

import com.fadadianqi.logistics.admin.controller.SellController.BillForm;
import com.fadadianqi.logistics.admin.controller.SellController.BillFormItem;
import com.fadadianqi.logistics.admin.printer.BillPrinter;
import com.fadadianqi.logistics.admin.printer.PrinterException;
import com.fadadianqi.commons.ConfigHelper;
import com.fadadianqi.commons.PrimaryKeyCreator;
import com.fadadianqi.logistics.customer.model.Account;
import com.fadadianqi.logistics.customer.model.Customer;
import com.fadadianqi.logistics.customer.model.Village;
import com.fadadianqi.logistics.customer.service.AccountService;
import com.fadadianqi.logistics.customer.service.CustomerService;
import com.fadadianqi.goods.model.Category;
import com.fadadianqi.goods.model.Goods;
import com.fadadianqi.goods.service.GoodsService;
import com.fadadianqi.logistics.inventory.service.InventoryService;
import com.fadadianqi.search.IndexObjectBufferPool;
import com.fadadianqi.logistics.sell.LowStocksException;
import com.fadadianqi.logistics.sell.dao.BillDAO;
import com.fadadianqi.logistics.sell.dao.GoodsDAO;
import com.fadadianqi.logistics.sell.dao.ItemDAO;
import com.fadadianqi.logistics.sell.model.Bill;
import com.fadadianqi.logistics.sell.model.Item;
import com.fadadianqi.logistics.sell.model.Payment;
import com.yeqiangwei.commons.util.ArithHelper;
import com.yeqiangwei.commons.util.Pagination;
import com.yeqiangwei.commons.util.StringHelper;
import com.yeqiangwei.commons.util.ValidatorHelper;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Service
public class BillService {

    private static final Logger log = Logger.getLogger(BillService.class);

    public List<Bill> findByVillageId(String villageId, Pagination pagination) {
        return billDAO.findByVillageId(villageId, pagination);
    }

    public int countByVillageId(String villageId) {
        return billDAO.countByVillageId(villageId);
    }

    public List<Bill> findByCustomerId(String cid, Pagination pagination) {
        return billDAO.findByCustomerId(cid, pagination);
    }

    public int countByCustomerId(String cid) {
        return billDAO.countByCustomerId(cid);
    }

    public List<Bill> findByTownId(String tid, Pagination pagination) {
        return billDAO.findByTownId(tid, pagination);
    }

    public int countByTownId(String tid) {
        return billDAO.countByTownId(tid);
    }

    /**
     * 处理退货业务
     *
     * @param ids
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void returnItems(String[] ids, Double returnMoney) {
        if (ValidatorHelper.isEmpty(ids)) {
            return;
        }
        String billId = null;
        double cost = 0; // 订单减少的成本

        for (String itemId : ids) {
            Item item = getItemById(itemId);
            item.setIsReturn(Boolean.TRUE);
            itemDAO.update(item);
            cost += item.getCost();
            // save inventoryId to database
            String inventoryId = item.getInventoryItemId();
            com.fadadianqi.logistics.inventory.model.Item inventory = inventoryService.getById(inventoryId);
            inventory.setStatus(com.fadadianqi.logistics.inventory.model.Item.STATUS_NORMAL);
            inventoryService.update(inventory);
            //
            if (billId == null) {
                billId = item.getBillId();
            }
            //
            String goodsId = item.getGoodsId();
            com.fadadianqi.logistics.sell.model.Goods billGoods = billGoodsDAO.getByBillIdAndGoodsId(billId, goodsId);
            if (null != billGoods) {
                billGoods.setNumber(billGoods.getNumber() - 1);
                billGoodsDAO.update(billGoods);
            }

            inventoryService.updateStorehouesTotal(inventory.getStorehouseId(), goodsId);
        }

        Bill bill = getById(billId);
        double realPayables = bill.getRealPayables().doubleValue();
        /*
		 * 如果账单已清则不计算客户相关债务
		 * 如果未清则计算相关债务
		 */
        if (!bill.getIsChecked()) {
            // 本次订单的欠款数目
            Customer customer = customerService.getById(bill.getCustomerId());
            if (customer != null) {
                //double thisBillDebt = realPayables - returnMoney - paymentService.sumPaid(bill);
                Double d = customer.getDebt(); //returnMoney - paymentService.sumPaid(bill);
                if (d == null) {
                    //计算负债
                    d = realPayables - returnMoney - paymentService.sumPaid(bill);
                } else {
                    d = ArithHelper.add(d, returnMoney);
                }
                customer.setDebt(d);
                customerService.saveCustomer(customer);
            }
        }

        int count = itemDAO.countNotReturn(billId); // 统计没有退回,正常销售的商品数量
        if (count == 0) {
            List<Payment> ps = paymentService.findByBillId(bill);
            if (ValidatorHelper.isNotEmpty(ps)) {
                for (Payment p : ps) {
                    paymentService.remove(p);
                }
            }

            List<Account> as = accountService.findByBillId(bill);
            if (ValidatorHelper.isNotEmpty(as)) {
                for (Account a : as) {
                    accountService.remove(a);
                }
            }

            bill.setIsReturn(Boolean.TRUE);
        }
        bill.setRealPayables(realPayables - returnMoney);
        bill.setCost(bill.getCost() - cost);
        billDAO.update(bill);

    }

    public Item getItemById(String itemId) {
        return itemDAO.getById(itemId);
    }

    public Item getItemByGoodsIdAndBillId(String goodsId, String billId) {
        return itemDAO.getItemByGoodsIdAndBillId(goodsId, billId);
    }

    public BillService() {
        try {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void saveBill(BillForm form) throws Exception {
        if (ValidatorHelper.isNotEmpty(form.getBillId())) {

        } else {
            create(form);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void updateSoldItems(com.fadadianqi.logistics.inventory.model.Item item) {
        List<Item> billItems = itemDAO.findByInventoryItemId(item.getId());
        if (ValidatorHelper.isEmpty(billItems)) {
            return;
        }
        for (Item billItem : billItems) {
            billItem.setCost(item.getCost());
            itemDAO.update(billItem);
            if (item.getStatus().intValue()
                    == com.fadadianqi.logistics.inventory.model.Item.STATUS_SOLD) {
                updateBillCost(billItem.getBillId());
            }
        }
    }

    private void updateBillCost(String billId) {
        List<Item> billItems = itemDAO.findByBillId(billId);
        if (ValidatorHelper.isEmpty(billItems)) {
            return;
        }
        double cost = 0;
        for (Item billItem : billItems) {
            if (billItem.getIsReturn()) {
                continue;
            }
            cost += billItem.getCost();
        }
        Bill bill = billDAO.getById(billId);
        bill.setCost(cost);
        billDAO.update(bill);
    }

    public void checked(Bill bill) {
        billDAO.update(bill);
    }

    public Double sumCostBetween(Date date1, Date date2) {
        Double d = billDAO.sumCostBetween(date1, date2);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public double sumPurchaseBetween(Date start, Date end) {
        Double d = itemDAO.sumPurchaseBetween(start, end);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public Double sumRealPayablesBetween(Date date1, Date date2) {
        Double d = billDAO.sumRealPayablesBetween(date1, date2);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    /**
     * 计算利润
     *
     * @param bill
     * @return
     */
    public Double getProfit(Bill bill) {
        Double cost = bill.getCost();
        Double realPayables = bill.getRealPayables();
        return realPayables - cost;
    }

    public List<Bill> findAllWithIsReturn(Boolean isReturn,
                                          Pagination pagination) {
        return billDAO.findAllWithIsReturn(isReturn, pagination);
    }

    public int countAllWithIsReturn(Boolean isReturn) {
        return billDAO.countAllWithIsReturn(isReturn);
    }

    public List<Bill> findAllWithIsChecked(Boolean isChecked,
                                           Pagination pagination) {
        return billDAO.findAllWithIsChecked(isChecked, pagination);
    }

    public int countAllWithIsChecked(Boolean isChecked) {
        return billDAO.countAllWithIsChecked(isChecked);
    }

    public List<Bill> findAll(Pagination pagination) {
        return billDAO.findAll(pagination);
    }

    public List<Bill> between(Date date1, Date date2, Pagination pagination) {
        return billDAO.between(date1, date2, pagination);
    }

    public int countBetween(Date date1, Date date2) {
        return billDAO.countBetween(date1, date2);
    }

    public List<Bill> between(Date date1, Date date2, String customerId,
                              Pagination pagination) {
        return billDAO.between(date1, date2, customerId, pagination);
    }

    public int countBetween(Date date1, Date date2, String customerId) {
        return billDAO.countBetween(date1, date2, customerId);
    }

    public int countAll() {
        return billDAO.countAll();
    }

    public List<Item> findItemsByBillId(String billId) {
        return itemDAO.findByBillId(billId);
    }

    private void create(BillForm form) throws PrinterException, LowStocksException {
        String customerName = form.getCustomerName();
        String villageId = form.getVillageId();
        Customer customer = customerService.getByNameAndVillageId(customerName, villageId);
        Bill bill = new Bill();
        if (customer == null && ValidatorHelper.isNotEmpty(form.getCustomerName())) {
            customer = new Customer();
            customer.setName(form.getCustomerName());
            if (ValidatorHelper.isNotEmpty(form.getMobile())) {
                String mb = form.getMobile().replace(",", " ").replace("，", " ").replace(" ", " ");
                customer.setMobile(mb);
            }
            if (ValidatorHelper.isNotEmpty(form.getVillageId())) {
                customer.setVillageId(form.getVillageId());
                Village village = customerService.getVillageById(form.getVillageId());
                customer.setTownId(village.getTownId());
            }
            customer.setMemo(StringHelper.EMPTY);
            customer.setDebt(-form.getRealPayables());
            customerService.saveCustomer(customer);
        } else if (customer != null) {
            if (ValidatorHelper.isNotEmpty(form.getMobile())) {
                String mb = form.getMobile().replace(",", " ").replace("，", " ").replace(" ", " ");
                customer.setMobile(mb);
            }
            //customer.setBalance(customer.getBalance().doubleValue()-form.getRealPayables());
            customer.setDebt(customer.getDebt().doubleValue() - form.getRealPayables());
            customerService.saveCustomer(customer);
        }
        if (customer != null) {
            bill.setCustomerId(customer.getId());
            bill.setVillageId(customer.getVillageId());
        }
        bill.setMemo(form.getMemo());
        bill.setAddTime(new Date());
        bill.setPayables(form.getPayables());
        bill.setRealPayables(form.getRealPayables());
        bill.setId(PrimaryKeyCreator.create());

        Double billCost = 0D;
        Double billPurchase = 0D;
        List<BillFormItem> itemList = form.getItemList();

        for (BillFormItem im : itemList) {
            String goodsId = im.getGoodsId();

            // 商品相关信息
            Goods goods = goodsService.getGoodsById(goodsId);

            com.fadadianqi.logistics.sell.model.Goods billGoods = new com.fadadianqi.logistics.sell.model.Goods();
            billGoods.setAddTime(bill.getAddTime());
            billGoods.setBillId(bill.getId());
            billGoods.setBrandId(goods.getBrandId());
            billGoods.setCategoryId(goods.getCategoryId());
            billGoods.setGoodsId(goods.getId());
            billGoods.setId(PrimaryKeyCreator.create());
            billGoods.setNumber(im.getNumber());
            billGoods.setUnitPrice(im.getPayables()); // 单价
            billGoodsDAO.create(billGoods);

            int count = 0;
            int statusNormal = com.fadadianqi.logistics.inventory.model.Item.STATUS_NORMAL;
            String storehouseId = im.getStorehouseId();
            if (storehouseId.equals("normal")) {
                // 默认出库原则先进先出
                count = inventoryService.countStatusNormalByGoodsId(goodsId);
            } else if (storehouseId.equals("none")) {
                // 未入库商品
                count = inventoryService.countByGoodsIdAndStorehouseIdAndStatus(goodsId, null, statusNormal);
            } else {
                count = inventoryService.countByGoodsIdAndStorehouseIdAndStatus(goodsId, storehouseId, statusNormal);
            }
            if (count < im.getNumber()) {
                throw new LowStocksException("exception.bill.low.stocks");
            }
            for (int i = 1; i <= im.getNumber(); i++) {
                Item item = new Item();
                item.setBillId(bill.getId());
                item.setGoodsId(im.getGoodsId());
                item.setPayables(im.getPayables());

                // 从库存中取出商品
                com.fadadianqi.logistics.inventory.model.Item inventoryItem = null;
                //
                if (storehouseId.equals("normal")) {
                    inventoryItem = inventoryService.getNormalItemByGoodsId(goodsId);
                } else if (storehouseId.equals("none")) {
                    inventoryItem = inventoryService.getNormalItemByGoodsIdAndStorehouseId(goodsId, null);
                } else {
                    inventoryItem = inventoryService.getNormalItemByGoodsIdAndStorehouseId(goodsId, storehouseId);
                    inventoryService.updateStorehouesTotal(storehouseId, goodsId);
                }

                String inventoryItemId = inventoryItem.getId();
                String stockBatchId = inventoryItem.getBatchId();
                item.setInventoryItemId(inventoryItemId);
                item.setBatchId(stockBatchId);

                // 商品成本
                item.setCost(inventoryItem.getCost());

                item.setPurchase(inventoryItem.getPurchase());

                item.setBrandId(goods.getBrandId());
                item.setCategoryId(goods.getCategoryId());

                item.setAddTime(bill.getAddTime());
                item.setId(PrimaryKeyCreator.create());
                itemDAO.create(item);

                // 标记已售出
                inventoryItem.setStatus(com.fadadianqi.logistics.inventory.model.Item.STATUS_SOLD);
                inventoryService.update(inventoryItem);

                billCost += item.getCost();
                billPurchase += item.getPurchase();

            }
        }
        bill.setCost(billCost);
        bill.setPurchase(billPurchase);
        billDAO.create(bill);
        form.setBillId(bill.getId());
        if (form.getNeedPrint()) { // 判断是否打印票据
            // 判断是否打印单品价格
            ConfigHelper.set("printer.goods.price", String.valueOf(form.getNeedPrintUnitPrice()));
            billPrinter.doPrint(bill.getId());
        }
        IndexObjectBufferPool.add(bill);

    }

    /**
     * @param billId
     * @return
     */
    public Bill getById(String billId) {
        return billDAO.getById(billId);
    }

    public List<com.fadadianqi.logistics.sell.model.Goods> findGoodsByBillId(String billId) {
        return billGoodsDAO.findGoodsByBillId(billId);
    }

    public void print(String billId, boolean printUnit) throws Exception {
        ConfigHelper.set("printer.goods.price", String.valueOf(printUnit));
        billPrinter.doPrint(billId);
    }

    @Autowired
    private BillPrinter billPrinter;

    /**
     * 统计指定日期内某种商品的销售数量
     *
     * @param start
     * @param end
     * @return
     */
    public int countItemBetween(Category category, Date start, Date end) {
        return itemDAO.countBetween(category, start, end);
    }

    public double sumRealPayablesBetween(Category category, Date start, Date end) {
        Double d = itemDAO.sumPayablesBetween(category, start, end);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public double sumCostBetween(Category category, Date start, Date end) {
        Double d = itemDAO.sumCostBetween(category, start, end);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public Double sumRealPayables(int year) {
        Double d = billDAO.sumRealPayables(year);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public Double sumPurchase(int year) {
        Double d = billDAO.sumPurchase(year);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    public Double sumCost(int year) {
        Double d = billDAO.sumCost(year);
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    /**
     * 库存总价值，总成本。
     *
     * @return
     */
    public Double sumCost() {
        Double d = inventoryItemDAO.sumCost();
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    /**
     * 库存总交易额
     *
     * @return
     */
    public Double sumPurchase() {
        Double d = inventoryItemDAO.sumPurchase();
        if (d != null) {
            d = ArithHelper.round(d, 2);
        }
        return d;
    }

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private BillDAO billDAO;

    @Resource(name = "billGoodsDAO")
    private GoodsDAO billGoodsDAO;

    @Resource(name = "billItemDAO")
    private ItemDAO itemDAO;

    @Resource(name = "inventoryItemDAO")
    private com.fadadianqi.logistics.inventory.dao.ItemDAO inventoryItemDAO;

    @Autowired
    private InventoryService inventoryService;

    public static class PrintConfig {

        private String printerIP;
        private String title;
        private String address;
        private String tel;

        public String getPrinterIP() {
            return printerIP;
        }

        public void setPrinterIP(String printerIP) {
            this.printerIP = printerIP;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getTel() {
            return tel;
        }

        public void setTel(String tel) {
            this.tel = tel;
        }
    }
}
